#include "board.h"
#include "hpm_pwm_drv.h"
#include "hpm_trgm_drv.h"
#include "hpm_trgmmux_src.h"
#include "hpm_adc16_drv.h"
#include "hpm_adc12_drv.h"

uint8_t trig_adc_channel[] = {BOARD_APP_ADC12_CH_1};
extern uint16_t adc_dma_buffer_len;
void init_trigger_source(PWM_Type *ptr)
{
    pwm_cmp_config_t pwm_cmp_cfg;
    pwm_output_channel_t pwm_output_ch_cfg;

    /* TODO: Set PWM Clock Source and divider */

    /* 33.33KHz reload at 200MHz */
    pwm_set_reload(ptr, 0, 49);

    /* Set a comparator */
    memset(&pwm_cmp_cfg, 0, sizeof(pwm_cmp_config_t));
    pwm_cmp_cfg.enable_ex_cmp  = false;
    pwm_cmp_cfg.mode           = pwm_cmp_mode_output_compare;
    pwm_cmp_cfg.update_trigger = pwm_shadow_register_update_on_shlk;

    /* Select comp8 and trigger at the middle of a pwm cycle */
    
    pwm_cmp_cfg.cmp = 25;
    pwm_config_cmp(ptr, 8, &pwm_cmp_cfg);//输出比较通道8作为输出

    /* Issue a shadow lock */
    pwm_issue_shadow_register_lock_event(HPM_PWM0);

    /* Set comparator channel to generate a trigger signal */
    pwm_output_ch_cfg.cmp_start_index = 8;   /* start channel */ //输出比较通道8
    pwm_output_ch_cfg.cmp_end_index   = 8;   /* end channel */ //输出比较通道8
    pwm_output_ch_cfg.invert_output   = false;
    pwm_config_output_channel(ptr, 8, &pwm_output_ch_cfg); //输出比较通道8

    /* Start the comparator counter */
}

void init_trigger_mux(TRGM_Type * ptr)
{
    trgm_output_t trgm_output_cfg;

    trgm_output_cfg.invert = false;
    trgm_output_cfg.type = trgm_output_same_as_input;

    HPM_IOC->PAD[IOC_PAD_PC02].FUNC_CTL = IOC_PC02_FUNC_CTL_TRGM0_P_03;
    trgm_enable_io_output(HPM_TRGM0, 1 << 3);

    trgm_output_cfg.input  = HPM_TRGM0_INPUT_SRC_PWM0_CH8REF;
    trgm_output_config(ptr, TRGM_TRGOCFG_ADC0_STRGI, &trgm_output_cfg);
    trgm_output_config(ptr, TRGM_TRGOCFG_ADC1_STRGI, &trgm_output_cfg);
    trgm_output_config(ptr, TRGM_TRGOCFG_ADC2_STRGI, &trgm_output_cfg);
    trgm_output_config(ptr,TRGM_TRGOCFG_ADC3_STRGI,&trgm_output_cfg);
    trgm_output_config(ptr, HPM_TRGM0_OUTPUT_SRC_TRGM0_P3, &trgm_output_cfg);
}

void init_adc_pins(void)
{
    /* ADC0/1/2.VIN7 */
    HPM_IOC->PAD[IOC_PAD_PE21].FUNC_CTL = IOC_PAD_FUNC_CTL_ANALOG_MASK;
    /* ADC0/1/2.VIN8 */
    HPM_IOC->PAD[IOC_PAD_PE24].FUNC_CTL = IOC_PAD_FUNC_CTL_ANALOG_MASK;
    /* ADC0/1/2.VIN9 */
    HPM_IOC->PAD[IOC_PAD_PE25].FUNC_CTL = IOC_PAD_FUNC_CTL_ANALOG_MASK;

    /* ADC3.INA2 */
    HPM_IOC->PAD[IOC_PAD_PE29].FUNC_CTL = IOC_PAD_FUNC_CTL_ANALOG_MASK;

}

uint32_t init_all_adc_clock(uint32_t div)
{
    uint32_t freq = 0;

    clock_set_adc_source(clock_adc0, clk_adc_src_ahb0);
    clock_set_adc_source(clock_adc1, clk_adc_src_ahb0);
    clock_set_adc_source(clock_adc2, clk_adc_src_ahb0);
    clock_set_adc_source(clock_adc3, clk_adc_src_ahb0);//ADC3 使用ana1
}

void init_common_config(adc12_conversion_mode_t conv_mode)
{
    adc12_config_t cfg;

    /* initialize an ADC instance */
    adc12_get_default_config(&cfg);

    cfg.res            = adc12_res_12_bits;
    cfg.conv_mode      = conv_mode;//序列转换模式
    cfg.adc_clk_div    = adc12_clock_divider_3;
    cfg.sel_sync_ahb   = false;
    if (cfg.conv_mode == adc12_conv_mode_sequence) {
        cfg.adc_ahb_en = true;
    }

    adc12_init(HPM_ADC0, &cfg);
    adc12_init(HPM_ADC1, &cfg);
    adc12_init(HPM_ADC2, &cfg);

    intc_m_enable_irq_with_priority(BOARD_APP_ADC12_IRQn, 2);
    adc16_config_t adc16_cfg;
    adc16_get_default_config(&adc16_cfg);
    adc16_cfg.res = adc16_res_12_bits;
    adc16_cfg.conv_mode = conv_mode;//与ADC12转换模式枚举类型一致，故直接互用。
    adc16_cfg.adc_clk_div = adc16_clock_divider_3;
    adc16_cfg.sel_sync_ahb = false;
    if (adc16_cfg.conv_mode == adc16_conv_mode_sequence) {
        adc16_cfg.adc_ahb_en = true;
    }
    adc16_init(BOARD_APP_ADC16_BASE,&adc16_cfg);
}

void init_ADC16_sequence_config(ADC16_Type *ADC,uint32_t* data_addr,uint8_t channel_cfg_num,uint8_t* channel_list,uint8_t channel_num)
{
    adc16_seq_config_t seq_cfg;
    adc16_dma_config_t dma_cfg;
    adc16_channel_config_t ch_cfg;

    /* get a default channel config */
    adc16_get_channel_default_config(&ch_cfg);

    /* initialize an ADC channel */
    ch_cfg.sample_cycle = 1;

    for (int i = 0; i < channel_num; i++) {
        ch_cfg.ch           = channel_list[i];
        adc16_init_channel(BOARD_APP_ADC16_BASE, &ch_cfg);
    }

    /* Set a sequence config */
    seq_cfg.seq_len    = channel_num;
    seq_cfg.restart_en = false;
    seq_cfg.cont_en    = true;
    seq_cfg.sw_trig_en = false;
    seq_cfg.hw_trig_en = true;

    for (int i = 0; i < seq_cfg.seq_len; i++) {
        seq_cfg.queue[i].seq_int_en = false;
        seq_cfg.queue[i].ch = channel_list[i];
    }

    /* Enable the single complete interrupt for the last conversion */
    seq_cfg.queue[seq_cfg.seq_len - 1].seq_int_en = false;

    /* Initialize a sequence */
    adc16_set_seq_config(BOARD_APP_ADC16_BASE, &seq_cfg);

    /* Set a DMA config */
    dma_cfg.start_addr         = (uint32_t *)core_local_mem_to_sys_address(HPM_CORE0, (uint32_t)data_addr);
    dma_cfg.buff_len_in_4bytes = adc_dma_buffer_len;
    dma_cfg.stop_en            = true;
    dma_cfg.stop_pos           = adc_dma_buffer_len -1;

    /* Initialize DMA for the sequence mode */
    adc16_init_seq_dma(BOARD_APP_ADC16_BASE, &dma_cfg);

    /* Enable sequence complete interrupt */
    //adc16_enable_interrupts(BOARD_APP_ADC16_BASE, adc16_event_seq_dma_abort);
}
void init_trigger_cfg(ADC12_Type *ptr, uint8_t trig_ch, bool inten)
{
    adc12_pmt_config_t pmt_cfg;

    pmt_cfg.trig_len = sizeof(trig_adc_channel);
    pmt_cfg.trig_ch = trig_ch;

    for (int i = 0; i < pmt_cfg.trig_len; i++) {
        pmt_cfg.adc_ch[i] = trig_adc_channel[i];
        pmt_cfg.inten[i] = false;
    }

    pmt_cfg.inten[pmt_cfg.trig_len - 1] = inten;

    adc12_set_pmt_config(ptr, &pmt_cfg);
}
void init_sequence_config(ADC12_Type *ADC,uint32_t* data_addr,uint8_t channel_cfg_num,uint8_t* channel_list,uint8_t channel_num)
{
    adc12_seq_config_t seq_cfg;
    adc12_dma_config_t dma_cfg;
    adc12_channel_config_t ch_cfg;

    /* get a default channel config */
    adc12_get_channel_default_config(&ch_cfg);//

    /* initialize an ADC channel */
    ch_cfg.diff_sel     = adc12_sample_signal_single_ended;
    ch_cfg.sample_cycle = 1;

    for (int i = 0; i < channel_num; i++) {
        ch_cfg.ch           = channel_list[i];
        adc12_init_channel(ADC, &ch_cfg);
    }

    /* Set a sequence config */
    seq_cfg.seq_len    = channel_num;
    seq_cfg.restart_en = false;
    seq_cfg.cont_en    = true;//等到下一个软件或者硬件触发的时候才会开始下一个通道的转化
    seq_cfg.sw_trig_en = false;
    seq_cfg.hw_trig_en = true;

    for (int i = 0; i < seq_cfg.seq_len; i++) {
        seq_cfg.queue[i].seq_int_en = false;
        seq_cfg.queue[i].ch = channel_list[i];
    }

     /* Enable the single complete interrupt for the last conversion */
    seq_cfg.queue[seq_cfg.seq_len - 1].seq_int_en = false;//使能最后一个ADC通道转换完成中断。

    /* Initialize a sequence */
    
    //使能trigger
    init_trigger_cfg(ADC,channel_cfg_num,true);
    adc12_set_seq_config(ADC, &seq_cfg);//配置通道
    
    /* Set a DMA config */ //内建DMA配置
    dma_cfg.start_addr         = (uint32_t *)core_local_mem_to_sys_address(HPM_CORE0,(uint32_t)data_addr);
    
    dma_cfg.buff_len_in_4bytes = adc_dma_buffer_len;
    
    dma_cfg.stop_en            = true;
    dma_cfg.stop_pos           = adc_dma_buffer_len-1;
    
    /* Initialize DMA for the sequence mode */
    adc12_init_seq_dma(ADC, &dma_cfg);
    
    /* Enable sequence complete interrupt */
    if(ADC == HPM_ADC0)
    {
        adc12_enable_interrupts(ADC, adc12_event_seq_dma_abort);//转换完成267个数据时，进入中断 仅有ADC0进入中断
    }
    
}

void init_adc_pin_clock_trigger(void)
{
    init_adc_pins();

    init_all_adc_clock(2);

    init_trigger_source(HPM_PWM0);

    init_trigger_mux(HPM_TRGM0);

    init_common_config(adc12_conv_mode_sequence);
}

void ADC_DMA_RESET(void* ADC_Base,uint32_t Addr)
{
    adc12_dma_config_t dma12_cfg;
    adc16_dma_config_t dma16_cfg;

    ADC16_Type *ADC16;
    ADC12_Type *ADC12;

    if(HPM_ADC3 == ADC_Base)
    {
        ADC16 = ADC_Base;
        dma16_cfg.start_addr       = (uint32_t *)core_local_mem_to_sys_address(HPM_CORE0, (uint32_t)Addr);
        dma16_cfg.buff_len_in_4bytes = adc_dma_buffer_len;/*不允许大于4096*/
        dma16_cfg.stop_en            = true;
        dma16_cfg.stop_pos           = adc_dma_buffer_len-1;
        
        ADC16->SEQ_DMA_CFG |= ADC16_SEQ_DMA_CFG_DMA_RST_MASK;
        ADC16->SEQ_DMA_CFG &= ~ADC16_SEQ_DMA_CFG_DMA_RST_MASK;
        ADC16->SEQ_DMA_ADDR = (uint32_t)dma16_cfg.start_addr & ADC16_SEQ_DMA_ADDR_TAR_ADDR_MASK;
        ADC16->SEQ_DMA_CFG = (ADC16->SEQ_DMA_CFG & ~ADC16_SEQ_DMA_CFG_BUF_LEN_MASK)
                         | ADC16_SEQ_DMA_CFG_BUF_LEN_SET(dma16_cfg.buff_len_in_4bytes - 1);
        if (dma16_cfg.stop_en) {
            ADC16->SEQ_DMA_CFG = (ADC16->SEQ_DMA_CFG & ~ADC16_SEQ_DMA_CFG_STOP_POS_MASK)
                             | ADC16_SEQ_DMA_CFG_STOP_EN_MASK
                             | ADC16_SEQ_DMA_CFG_STOP_POS_SET(dma16_cfg.stop_pos);
        }
        /*以上函数体为adc16_init_seq_dma的函数内容*/
        //adc16_init_seq_dma(ADC_Base, &dma16_cfg);
    }else{
        ADC12 = ADC_Base;
        dma12_cfg.start_addr         = (uint32_t *)core_local_mem_to_sys_address(HPM_CORE0, (uint32_t)Addr);
        dma12_cfg.buff_len_in_4bytes = adc_dma_buffer_len;/*不允许大于4096*/
        dma12_cfg.stop_en            = true;
        dma12_cfg.stop_pos           = adc_dma_buffer_len-1;
        
        ADC12->SEQ_DMA_CFG |= ADC12_SEQ_DMA_CFG_DMA_RST_MASK;
        ADC12->SEQ_DMA_CFG &= ~ADC12_SEQ_DMA_CFG_DMA_RST_MASK;
        ADC12->SEQ_DMA_ADDR = (uint32_t)dma12_cfg.start_addr & ADC12_SEQ_DMA_ADDR_TAR_ADDR_MASK;
        ADC12->SEQ_DMA_CFG = (ADC12->SEQ_DMA_CFG & ~ADC12_SEQ_DMA_CFG_BUF_LEN_MASK)
                         | ADC12_SEQ_DMA_CFG_BUF_LEN_SET(dma12_cfg.buff_len_in_4bytes - 1);
        if (dma12_cfg.stop_en) {
            ADC12->SEQ_DMA_CFG = (ADC12->SEQ_DMA_CFG & ~ADC12_SEQ_DMA_CFG_STOP_POS_MASK)
                             | ADC12_SEQ_DMA_CFG_STOP_EN_MASK
                             | ADC12_SEQ_DMA_CFG_STOP_POS_SET(dma12_cfg.stop_pos);
        }

        //adc12_init_seq_dma(ADC_Base, &dma12_cfg);
    }
}

void trigger_start(PWM_Type * ptr)
{
    pwm_start_counter(ptr);
}

void trigger_stop(PWM_Type * ptr)
{
    pwm_stop_counter(ptr);
}